use std::ffi::CString;
use std::sync::atomic::{AtomicUsize, Ordering};
macro_rules! alloc_test_malloc {
    ($ bytes : expr) => {{
        alloc_test_malloc($bytes)
    }};
}
macro_rules! alloc_test_free {
    ($ ptr : expr) => {{
        alloc_test_free($ptr)
    }};
}
macro_rules! alloc_test_realloc {
    ($ ptr : expr , $ bytes : expr) => {{
        alloc_test_realloc($ptr, $bytes)
    }};
}
macro_rules! alloc_test_calloc {
    ($ nmemb : expr , $ bytes : expr) => {{
        alloc_test_calloc($nmemb, $bytes)
    }};
}
macro_rules! alloc_test_strdup {
    ($ string : expr) => {{
        alloc_test_strdup($string)
    }};
}
macro_rules! c_assert {
    ($ expr : expr) => {{
        num_assert.fetch_add(1, Ordering::SeqCst);
        if !$expr {
            panic!(
                "Assertion failed: {} at {}:{}",
                stringify!($expr),
                file!(),
                line!()
            );
        }
    }};
}
type UnitTestFunction = fn();
static num_assert: AtomicUsize = AtomicUsize::new(0);
#[repr(C)]
type BloomFilterValue = *mut std::ffi::c_void;
type BloomFilterHashFunc = fn(BloomFilterValue) -> u32;
static TEST_FUNCTIONS: &[UnitTestFunction] = &[
    test_bloom_filter_new_free,
    test_bloom_filter_insert_query,
    test_bloom_filter_read_load,
    test_bloom_filter_intersection,
    test_bloom_filter_union,
    test_bloom_filter_mismatch,
];
#[test]
fn test_bloom_filter_new_free() {
    unsafe {
        let filter1: *mut BloomFilter;
        let filter2: *mut BloomFilter;
        let result: *mut BloomFilter;
        filter1 = bloom_filter_new(128, string_hash, 4);
        let c_test1 = CString::new("test 1").unwrap();
        bloom_filter_insert(filter1, c_test1.as_ptr());
        filter2 = bloom_filter_new(128, string_hash, 4);
        let c_test2 = CString::new("test 2").unwrap();
        bloom_filter_insert(filter2, c_test2.as_ptr());
        result = bloom_filter_union(filter1, filter2);
        assert!(bloom_filter_query(result, c_test1.as_ptr()) != 0);
        assert!(bloom_filter_query(result, c_test2.as_ptr()) != 0);
        bloom_filter_free(result);
        alloc_test_set_limit(0);
        result = bloom_filter_union(filter1, filter2);
        assert!(result.is_null());
        bloom_filter_free(filter1);
        bloom_filter_free(filter2);
    }
}
#[test]
fn test_bloom_filter_mismatch() {
    unsafe {
        let filter1: *mut BloomFilter;
        let filter2: *mut BloomFilter;
        filter1 = bloom_filter_new_rust(128, string_hash, 4);
        filter2 = bloom_filter_new_rust(64, string_hash, 4);
        assert!(bloom_filter_intersection(filter1, filter2) == ptr::null_mut());
        assert!(bloom_filter_union(filter1, filter2) == ptr::null_mut());
        bloom_filter_free_rust(filter2);
        filter2 = bloom_filter_new_rust(128, string_nocase_hash, 4);
        assert!(bloom_filter_intersection(filter1, filter2) == ptr::null_mut());
        assert!(bloom_filter_union(filter1, filter2) == ptr::null_mut());
        bloom_filter_free_rust(filter2);
        filter2 = bloom_filter_new_rust(128, string_hash, 32);
        assert!(bloom_filter_intersection(filter1, filter2) == ptr::null_mut());
        assert!(bloom_filter_union(filter1, filter2) == ptr::null_mut());
        bloom_filter_free_rust(filter2);
        bloom_filter_free_rust(filter1);
    }
}
fn main() {
    let tests: Vec<fn()> = vec![];
    run_tests(&tests);
    unsafe {
        println!("num_assert: {}", NUM_ASSERT);
    }
}
